﻿using Oracle.DataAccess.Client;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using System.Threading;
using WorkFlow.DBProxy;
using WorkFlow.Engine.NSActivity;
using WorkFlow.Engine.NSActivity.NSRoutes;
using WorkFlow.Engine.NSPermission;
using WorkFlow.Engine.NSUtilities;

namespace WorkFlow.Engine
{
    public class WfActivityController
    {
        #region 私有静态变量

        private static volatile List<WfActivity> _acts;
        private static volatile WfActivityController _controller;
        private static readonly object _lockObj = new object();
        private static List<WfActivity> _newActs;
        /*用来保存新活动,该新活动列表主要是用来通知客户端的,一旦有用户调用
                                                      * 该活动时候,从newActs移除*/

        #endregion 私有静态变量

        #region 创建实例 单件模式

        private WfActivityController()
        {
            _acts = new List<WfActivity>();
            _newActs = new List<WfActivity>();
            var ev = new AutoResetEvent(false);
            TimerCallback tcb = Recycle;
            // ReSharper disable ObjectCreationAsStatement
            new Timer(tcb, ev, 0, 300000); //5分钟运行移除活动回收器
            // ReSharper restore ObjectCreationAsStatement
        }

        /// <summary>
        /// 双重加锁 确保安全同时减少性能损失.
        /// </summary>
        /// <returns></returns>
        public static WfActivityController CreateActivityController()
        {
            if (_controller == null)
            {
                bool lockToken = false;

                try
                {
                    Monitor.Enter(_lockObj, ref lockToken);
                    _controller = new WfActivityController();
                }
                catch
                {
                    return null;
                }
                finally
                {
                    if (lockToken)
                    {
                        Monitor.Exit(_lockObj);
                    }
                }
            }
            return _controller;
        }

        #endregion 创建实例 单件模式

        #region 一般操作

        /// <summary>
        /// 获取集合里面的实例,如果有则返回一个活动,如果没有则新建一个实例 并加入到活动集合中. 根据用户名和活动ID获取
        /// 调用该方法: 拥有该 actID权限的UserID
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        /// <returns>当返回null时,说明别其他人锁定了</returns>
        public WfActivity GetActivity(int actID, int userID)
        {
            //如果controller尚未初始化
            if (_controller == null)
            {
                CreateActivityController();
            }
            /*
             *
             * 1. 检索acts是否包含,Y:检查是否被锁定,是否拥有权限,符合时返回
             * 2. 先检索newActs集合中是否包含,y:添加到acts中,同时返回
             * 3. 1和2都不满足时,创建新的活动
             */
            //1.如果_acts不为空的话
            if (_acts.Count != 0)
            {
                WfActivity act = GetCollectionAct(_acts, actID);
                if (act != null)
                {
                    //如果act 不为 null 所以act已经存在了
                    //如果用户有访问该活动的权限
                    if (!act.IsUserHasPrivilege(userID)) return null;

                    //如果锁定
                    if (act.IsLocked == WfFieldCode.DbTrue)
                    {
                        if (act.LockOwner < 0 || act.LockOwner == userID) act.LockOwner = userID;
                        act.LastVisitedDateTime = DateTime.Now;
                        return act;
                    }
                    //如果未被锁定
                    //------------------修改活动的时候加把锁--只加活动
                    //-----修改活动的时候加把锁--只加活动---超时锁-----------------------
                    bool lockToken = false;
                    try
                    {
                        Monitor.TryEnter(act, 200, ref lockToken);
                        if (lockToken)
                        {
                            act.IsLocked = WfFieldCode.DbTrue;
                            act.LockOwner = userID;
                            act.LastVisitedDateTime = DateTime.Now;
                            return act;
                        }
                    }
                    finally
                    {
                        if (lockToken)
                        {
                            Monitor.Exit(act);
                        }
                    }

                    //-----修改活动的时候加把锁--只加活动---超时锁-----------end--------
                    //lock (act)
                    //{
                    //    act.IsLocked = WfFieldCode.DbTrue;
                    //    act.LockOwner = userID;
                    //    act.LastVisitedDateTime = DateTime.Now;
                    //    return act;
                    //}
                }
            }

            //2 .如果不为_newActs为空
            if (_newActs.Count != 0)
            {
                WfActivity act = GetCollectionAct(_newActs, actID);
                if (act != null)
                {
                    //将活动添加到_acts中
                    //-----修改活动的时候加把锁--只加活动---超时锁-----------------------
                    bool lockToken = false;
                    try
                    {
                        Monitor.TryEnter(act, 200, ref lockToken);
                        if (lockToken)
                        {
                            //如果不考虑并发情况这里没有必要进行判断了
                            if (act.IsLocked == WfFieldCode.DbFalse)
                            {
                                act.IsLocked = WfFieldCode.DbTrue;
                                act.LockOwner = userID;
                                act.LastVisitedDateTime = DateTime.Now;
                                //添加到_acts中
                                _acts.Add(act);
                                //移除_newActs中的项
                                _newActs.Remove(act);
                                return act;
                            }
                        }
                    }
                    finally
                    {
                        if (lockToken)
                        {
                            Monitor.Exit(act);
                        }
                    }

                    //-----修改活动的时候加把锁--只加活动---超时锁-----------end--------

                    //lock (act)
                    //{
                    //    //如果不考虑并发情况这里没有必要进行判断了
                    //    if (act.IsLocked == WfFieldCode.DbFalse)
                    //    {
                    //        act.IsLocked = WfFieldCode.DbTrue;
                    //        act.LockOwner = userID;
                    //        act.LastVisitedDateTime = DateTime.Now;

                    //        //添加到_acts中
                    //        _acts.Add(act);
                    //        //移除_newActs中的项
                    //        _newActs.Remove(act);
                    //        return act;
                    //    }
                    //}
                }
            }

            //如果两个集合都不存在,这创建新活动.
            var newAct = new WfActivity(actID, userID);
            return newAct.IsCreated ? newAct : null;
        }

        /// <summary>
        /// 添加活动 如果创建时活动被锁定则添加到_acts,否则添加到_newActs中
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public WfActivity Add(WfActivity act)
        {
            if (act.IsCreated)
            {
                //如果活动不存在 如果活动被锁定或者活动是路由活动 添加到_acts中
                if (GetCollectionAct(_acts, act.ID) == null &&
                    (act.IsLocked == WfFieldCode.DbTrue || act.MainType == WfFieldCode.DbMainRouteType))
                {
                    _acts.Add(act);
                }
                else if (GetCollectionAct(_newActs, act.ID) == null && act.IsLocked == WfFieldCode.DbFalse &&
                         act.MainType == WfFieldCode.DbMainCommonType)
                {
                    _newActs.Add(act);
                }
            }
            return act;
        }

        /// <summary>
        /// 确定活动在活动集合中的位置
        /// </summary>
        /// <param name="list"></param>
        /// <param name="actID"></param>
        /// <returns>存在返回>=0,不存在返回-1</returns>
        private static WfActivity GetCollectionAct(IReadOnlyList<WfActivity> list, int actID)
        {
            if (list == null || list.Count == 0) return null;

            int count = list.Count;
            for (int i = 0; i < count; i++)
            {
                if (list[i].ID == actID) return list[i];
            }
            return null;
        }

        #endregion 一般操作

        #region 更改活动状态 直接通过活动

        /// <summary>
        /// 激活下一个活动
        /// </summary>
        /// <param name="act"></param>
        /// <param name="inputValue"></param>
        /// <returns></returns>
        public bool ActivateNext(WfActivity act, int? inputValue = null)
        {
            if (act == null) return false;
            List<string> actIDs = GetNextActitities(act);
            int count = actIDs == null ? 0 : actIDs.Count;
            ////如果当前是最后一个活动的话 那么返回的nextRActID就为NULL  这时时结束流程
            //    ///如果是最后一个活动,应该也不输出了 我觉得
            if (count == 0)
            {
                DB.ExecuteSql(string.Format(@"update t_processes set F_STATUS={0} WHERE F_ID={1}",
                                            WfFieldCode.DbCompleteState, act.ProcessId)); //将流程状态设置为完成
                return true;
            }

            try
            {
                if (count > 1)
                {
                    //如果count>1 说明后续互动数目至少是2个 也就是不可能其中一个包括结束活动
                    for (int i = 0; i < count; i++)
                    {
                        if (actIDs == null) continue;
                        WfActivity newAct = GetActivity(int.Parse(actIDs[i]), WfFieldCode.DbNone);
                        if (newAct == null) return false;
                        newAct.Ready(act.ID);
                        //如果为路由活动,则按路由活动规则进行处理;否则不进行任何操作.
                        WfRouteController.GetCurrentAcitvityType(newAct,act.ID, inputValue);
                    }
                }
                else
                {
                    if (actIDs != null)
                    {
                        WfActivity newAct = GetActivity(int.Parse(actIDs[0]), WfFieldCode.DbNone);
                        /*如果actIDs存在, 但却未取得活动,说明WfActivity没被被创建,这种情况应该在活动是结束活动的时候出现
                         * 但此时 流程应该被结束了 */
                        if (newAct == null)
                        {
                            return true;
                        }

                        newAct.Ready(act.ID);
                        //如果为路由活动,则按路由活动规则进行处理;否则不进行任何操作.
                        if (WfRouteController.GetCurrentAcitvityType(newAct,act.ID, inputValue) == WfFieldCode.DbMainCommonType)
                        {
                            return true;
                        }

                        //----------如果为rollback活动 进行回滚
                        if (newAct.MainType == WfFieldCode.DBMainTypeRollback)
                        {
                            return act.RollBack();
                        }
                    }
                }
            }
            catch
            {
                return false;
            }
            return true;
        }

        #region 根据活动更改状态

        /// <summary>
        /// 取消运行状态
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool Cancel(WfActivity act)
        {
            if (act.IsLocked == WfFieldCode.DbTrue && act.Status == WfFieldCode.DbRunState)
            {
                if (ChangeStatus(act.ID, WfFieldCode.DbReadyState, act.LockOwner, WfFieldCode.DbFalse))
                {
                    act.Status = WfFieldCode.DbReadyState;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 当活动complete时,激活后续后继活动
        /// </summary>
        /// <param name="act"></param>
        /// <param name="outputValue"></param>
        /// <returns></returns>
        public bool Complete(WfActivity act, int? outputValue = null)
        {
            //如果需要输出 用户却没有传入输出值则直接返回false
            if (act.NeeOutput == WfFieldCode.DbTrue && outputValue == null) return false;

            if (act.IsLocked != WfFieldCode.DbTrue || act.Status == WfFieldCode.DbCompleteState ||
                act.Status == WfFieldCode.DbTerminateState) return false;
            var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = act.ID}, //0
                    new OracleParameter("var_userId", OracleDbType.Int32) {Value = act.LockOwner}, //1
                    new OracleParameter("var_outputValue", OracleDbType.Int32) {Value = outputValue}, //2
                    new OracleParameter("var_r_act_id", OracleDbType.Int32, ParameterDirection.Input)
                        {
                            Value = act.RuleActID
                        }, //3
                    new OracleParameter("var_run_process_id", OracleDbType.Int32, ParameterDirection.Input)
                        {
                            Value = act.ProcessId
                        }, //4
                    new OracleParameter("var_influenceRows", OracleDbType.Int32) //5
                };
            obj[5].Direction = ParameterDirection.Output;
            DB.ExecuteProc("ActComplete", obj);
            if (int.Parse(obj[5].Value.ToString()) <= -1) return false;

            act.Status = WfFieldCode.DbCompleteState;
            //如果非路由活动的话 (因为路由活动后续可能有多个分支或者按条件激活) 激活当前活动的后续活动
            if (act.SubType != WfFieldCode.DbOrSplit && act.SubType != WfFieldCode.DbXorSplit)
            {
                ActivateNext(act, outputValue); //激活下一项活动
            }
            _acts.Remove(act); //从内存移除该项活动

            return true;
        }

        /// <summary>
        /// 设置最近后续活动的授权用户同时完成该活动
        /// </summary>
        /// <param name="accessor">授权用户</param>
        /// <param name="act">当前活动</param>
        /// <param name="nextActID">下一活动ID</param>
        /// <param name="outputValue">输出值</param>
        /// <returns></returns>
        public bool CompleteWithSetNextRunActsPrivilege(WfActAccessorStruct accessor, WfActivity act, int nextActID,
                                                        int? outputValue = null)
        {
            //如果需要输出 用户却没有传入输出值则直接返回false
            if (act.NeeOutput == WfFieldCode.DbTrue && outputValue == null) return false;
            //-------------------设置活动库accessor
            //---------如果该组织accessories的祖先为0 说明没有祖先 那么该accessor就是祖先 那也就没必要设置了
            if (accessor._ancestorID > 0)
            {
                if (!WfPermissionController.CreatePermissionController()
                                           .SetNewPrivilegesToRunAct(accessor, nextActID, act.LockOwner)) return false;
            }

            if (act.IsLocked != WfFieldCode.DbTrue || act.Status == WfFieldCode.DbCompleteState ||
                act.Status == WfFieldCode.DbTerminateState) return false;
            var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = act.ID}, //0
                    new OracleParameter("var_userId", OracleDbType.Int32) {Value = act.LockOwner}, //1
                    new OracleParameter("var_outputValue", OracleDbType.Int32) {Value = outputValue}, //2
                    new OracleParameter("var_r_act_id", OracleDbType.Int32, ParameterDirection.Input)
                        {
                            Value = act.RuleActID
                        }, //3
                    new OracleParameter("var_run_process_id", OracleDbType.Int32, ParameterDirection.Input)
                        {
                            Value = act.ProcessId
                        }, //4
                    new OracleParameter("var_influenceRows", OracleDbType.Int32) //5
                };
            obj[5].Direction = ParameterDirection.Output;
            DB.ExecuteProc("ActComplete", obj);
            if (int.Parse(obj[5].Value.ToString()) <= -1) return false;

            act.Status = WfFieldCode.DbCompleteState;
            //如果非路由活动的话 (因为路由活动后续可能有多个分支或者按条件激活) 激活当前活动的后续活动
            if (act.SubType != WfFieldCode.DbOrSplit && act.SubType != WfFieldCode.DbXorSplit)
            {
                ActivateNext(act, outputValue); //激活下一项活动
            }
            _acts.Remove(act); //从内存移除该项活动

            return true;
        }

        /// <summary>
        /// 就绪和状态 (回退状态等价于就绪状态) 从冻结状态变成就绪状态
        /// </summary>
        /// <param name="act"></param>
        /// <param name="activatorID">激活该活动的上一个运行库活动ID</param>
        /// <returns></returns>
        public bool Ready(WfActivity act, int activatorID)
        {
            var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = act.ID}, //0
                    new OracleParameter("var_activator", OracleDbType.Int32) {Value = activatorID}, //1
                    new OracleParameter("var_influenceRows", OracleDbType.Int32, ParameterDirection.Output) //2
                };
            DB.ExecuteProc("ActivateAct", obj);

            if (act.Status == WfFieldCode.DbFrozenState && int.Parse(obj[2].Value.ToString()) > 0)
            {
                act.Status = WfFieldCode.DbReadyState;
                return true;
            }
            return false;
        }

        /// <summary>
        /// 将事件从"挂起状变为"运行状态"
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool Resume(WfActivity act)
        {
            if (act.IsLocked == WfFieldCode.DbTrue && act.Status == WfFieldCode.DbSuspendState)
            {
                if (ChangeStatus(act.ID, WfFieldCode.DbRunState, act.LockOwner, WfFieldCode.DbFalse))
                {
                    act.Status = WfFieldCode.DbRunState;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 运行
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool Run(WfActivity act)
        {
            if (act.IsLocked == WfFieldCode.DbTrue &&
                (act.Status == WfFieldCode.DbReadyState || act.Status == WfFieldCode.DbRollbackState))
            {
                if (ChangeStatus(act.ID, WfFieldCode.DbRunState, act.LockOwner, WfFieldCode.DbFalse))
                {
                    act.Status = WfFieldCode.DbRunState;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool Suspend(WfActivity act)
        {
            if (act.IsLocked == WfFieldCode.DbTrue && act.Status != WfFieldCode.DbSuspendState)
            {
                if (ChangeStatus(act.ID, WfFieldCode.DbCompleteState, act.LockOwner, WfFieldCode.DbTrue))
                {
                    act.Status = WfFieldCode.DbSuspendState;
                    return true;
                }
            }
            return false;
        }

        /// <summary>
        /// 终止活动时是否要终止流程
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool Terminate(WfActivity act)
        {
            if (act.IsLocked == WfFieldCode.DbTrue && act.Status != WfFieldCode.DbCompleteState &&
                act.Status != WfFieldCode.DbTerminateState)
            {
                if (ChangeStatus(act.ID, WfFieldCode.DbTerminateState, act.LockOwner, WfFieldCode.DbFalse))
                {
                    act.Status = WfFieldCode.DbTerminateState;
                    return true;
                }
            }
            return false;
        }

        #endregion 根据活动更改状态

        #region 更改活动状态 通过活动ID和用户ID

        /// <summary>
        /// 取消运行状态
        /// </summary>
        /// <returns></returns>
        public bool Cancel(int actID, int userID)
        {
            return Cancel(GetActivity(actID, userID));
        }

        /// <summary>
        /// 当活动complete时,激活后续后继活动
        /// </summary>
        /// <returns></returns>
        public bool Complete(int actID, int userID, int? outputValue = null)
        {
            return Complete(GetActivity(actID, userID), outputValue);
        }

        /// <summary>
        /// 设置最近后续活动的授权用户同时完成该活动
        /// </summary>
        /// <param name="accessor">授权记录</param>
        /// <param name="actID">活动ID</param>
        /// <param name="nextActID">需要设置的下一活动ID</param>
        /// <param name="userID">用户ID</param>
        /// <param name="outputValue">输出值</param>
        /// <returns></returns>
        public bool CompleteWithSetNextRunActsPrivilege(WfActAccessorStruct accessor, int actID, int nextActID,
                                                        int userID,
                                                        int? outputValue = null)
        {
            return CompleteWithSetNextRunActsPrivilege(accessor, GetActivity(actID, userID), nextActID, outputValue);
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public bool Ready(int actID, int userID, int activatorID)
        {
            return Ready(GetActivity(actID, userID), activatorID);
        }

        /// <summary>
        /// 将事件从"挂起状变为"运行状态" 这个变迁要去该用户是该活动挂起的操作者
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool Resume(int actID, int userID)
        {
            return Resume(GetActivity(actID, userID));
        }

        /// <summary>
        /// 运行
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool Run(int actID, int userID)
        {
            return Run(GetActivity(actID, userID));
        }

        /// <summary>
        /// 在定时清理是,如果状态为 suspend(挂起)状态时,不清理锁定 除非本人进行解锁 (resume)
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool Suspend(int actID, int userID)
        {
            return Suspend(GetActivity(actID, userID));
        }

        /// <summary>
        /// 终止活动时是否要终止流程?
        /// </summary>
        /// <returns></returns>
        public bool Terminate(int actID, int userID)
        {
            return Terminate(GetActivity(actID, userID));
        }

        /// <summary>
        /// 更改活动状态
        /// </summary>
        /// <param name="actID">活动ID</param>
        /// <param name="toStatus">待转换到达的状态</param>
        /// <param name="userID">用户ID</param>
        /// <param name="dbIsLocked">是否被锁定</param>
        /// <returns></returns>
        private static bool ChangeStatus(int actID, int toStatus, int userID, int dbIsLocked)
        {
            var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = actID}, //0
                    new OracleParameter("var_status", OracleDbType.Int32) {Value = toStatus}, //1
                    new OracleParameter("var_ownerid", OracleDbType.Int32) {Value = userID}, //2
                    new OracleParameter("var_islocked", OracleDbType.Int32) {Value = dbIsLocked}, //3
                    new OracleParameter("var_influencerows", OracleDbType.Int32, ParameterDirection.Output) //4
                };
            DB.ExecuteProc("changeactstatus", obj);
            return int.Parse(obj[4].Value.ToString()) > 0;
        }

        #endregion 更改活动状态 通过活动ID和用户ID

        #endregion 更改活动状态 直接通过活动

        #region others

        /// <summary>
        /// 获取下一活动(s)
        /// </summary>
        /// <param name="act">当前活动</param>
        /// <returns></returns>
        private static List<string> GetNextActitities(WfActivity act)
        {
            var obj = new[]
                {
                    new OracleParameter("var_actId", OracleDbType.Int32) {Value = act.ID}, //0
                    new OracleParameter("var_procId", OracleDbType.Int32) {Value = act.ProcessId}, //1
                    new OracleParameter("returnValues", OracleDbType.Varchar2, 500) //2 对应返回值为varchar2类型,要这样,方向在外面设置
                };
            obj[2].Direction = ParameterDirection.Output;
            DB.ExecuteProc("GetNextActitities", obj);

            return obj[2].Value == null ? null : SplitStringToList(obj[2].Value.ToString(), new[] { ';' });
        }

        /// <summary>
        /// 分割以某符号作为分割符的字符串 例如: 12;33;32;
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="opt">分隔符</param>
        /// <returns></returns>
        private static List<string> SplitStringToList(string str, char[] opt)
        {
            string[] strs = str.Split(opt);
            int count = strs.Length - 1;
            if (count < 1) return null;
            var list = new List<string>();
            for (int i = 0; i < count; i++)
            {
                list.Add(strs[i]);
            }
            return list;
        }

        /// 本来应该是推送 不过现在没有好的方法 因而 暂时先改为有客户端定时请求 返回只读包装,反正用户在外面修改
        public static ReadOnlyCollection<WfActivity> GetReadyActList()
        {
            if (_newActs == null || _newActs.Count == 0) return null;
            return _newActs.AsReadOnly();
        }

        /// <summary>
        /// 回收未使用的活动或者解锁被锁定的活动.
        /// </summary>
        /// <param name="obj"></param>
        private static void Recycle(object obj)
        {
            WfCleaner.Recycle(_acts, _newActs);
        }

        /// <summary>
        /// 获取离该活动最近的后续活动集合
        /// </summary>
        /// <param name="curActivity">当前活动</param>
        /// <returns></returns>
        public ReadOnlyCollection<WfActivity> GetNextCommonActs(WfActivity curActivity)
        {
            if (curActivity == null || curActivity.MainType != WfFieldCode.DbMainCommonType) return null;
            List<string> actIDs = GetNextActitities(curActivity);
            int count = actIDs == null ? 0 : actIDs.Count;

            if (count == 0) return null; //没后续活动么直接返回就是了

            bool ident = false;
            var list = new List<WfActivity>();

            for (int i = 0; i < count; i++)
            {
                WfActivity newAct = GetActivity(int.Parse(actIDs[i]));
                if (newAct.MainType == WfFieldCode.DbMainCommonType)
                {
                    ident = true;
                    if (GetCollectionAct(list, newAct.ID) == null) list.Add(newAct);
                }
            } //end for loop
            if (ident) return list.AsReadOnly();
            /*
             * 如果某个活动后面的活动都不是 "一般活动" 那么说明该活动的后续活动为路由活动
             * 此时在寻找该活动的后续活动 再搜索一次即可 否则就说明设计存在问题
             * 一个common活动后面只应该有一个活动 所以 此时应该是 [当前活动]-[1个路由活动]-[n个一般活动]
             */
            WfActivity act = GetActivity(int.Parse(actIDs[0])); //估计 肯定是路由活动了
            List<string> nextList = GetNextActitities(act);
            count = nextList == null ? 0 : nextList.Count;
            if (count == 0) return null;

            for (int i = 0; i < count; i++)
            {
                WfActivity newAct = GetActivity(int.Parse(nextList[i]));
                if (newAct == null || !newAct.IsCreated) continue;

                if (newAct.MainType == WfFieldCode.DbMainCommonType)
                {
                    if (GetCollectionAct(list, newAct.ID) == null) list.Add(newAct);
                }
            } //end for loop
            return list.AsReadOnly();
        }

        /// <summary>
        /// 获取最近的后续活动所对应的组织(具体)
        /// </summary>
        /// <param name="curActID">当前活动ID</param>
        /// <returns>(具体)组织列表</returns>
        public ReadOnlyCollection<WfOrgStruct> GetNextCommonActivitiesAllOrgs(int curActID)
        {
            ReadOnlyCollection<WfActivity> actList = GetNextCommonActs(GetActivity(curActID));
            int count = actList == null ? 0 : actList.Count;
            if (count == 0) return null;

            var list = new List<WfOrgStruct>();
            //将 count 个活动所对应的组织合并到一起 当然 要去具体的组织
            for (int i = 0; i < count; i++)
            {
                List<WfOrgStruct> orgs = actList[i].GetSpecificOrgs();
                int rows = orgs == null ? 0 : orgs.Count;
                for (int r = 0; r < rows; r++)
                {
                    list.Add(orgs[r]);
                }
            }
            return list.AsReadOnly();
        }

        #region 不允许暴露方法

        /// <summary>
        /// 警告: @思恒 :: 不允许暴露该方法 ! 该方法属于有最高权限的方法,只允许该类内部调用,绝不准许外部调用
        /// </summary>
        /// <param name="actID"></param>
        /// <returns>当返回null时,说明别其他人锁定了</returns>
        private WfActivity GetActivity(int actID)
        {
            //如果controller尚未初始化
            if (_controller == null)
            {
                CreateActivityController();
            }
            //1. 如果_acts不为空
            if (_acts.Count != 0)
            {
                WfActivity act = GetCollectionAct(_acts, actID);
                if (act != null) return act;
            }

            //2 .如果不为_newActs为空
            if (_newActs.Count != 0)
            {
                WfActivity act = GetCollectionAct(_newActs, actID);
                if (act != null) return act;
            }

            //如果两个集合都不存在,这创建新活动.
            var newAct = new WfActivity(actID, WfFieldCode.DbNone);
            return newAct.IsCreated ? newAct : null;
        }

        #endregion 不允许暴露方法

        #endregion others

        #region 中国特有模式 回退

        /// <summary>
        /// 将当前活动actID状态设置为冻结状态(frozenState) 设置上一活动为回退状态(rollBackState) 相当于非回退时的ready状态.
        /// </summary>
        /// <param name="actID"></param>
        /// <param name="userID"></param>
        /// <returns></returns>
        public bool RollBack(int actID, int userID)
        {
            return RollBack(GetActivity(actID, userID));
        }

        /// <summary>
        /// 将当前活动actID状态设置为冻结状态(frozenState) 设置上一活动为回退状态(rollBackState) 相当于非回退时的ready状态.
        /// </summary>
        /// <param name="act"></param>
        /// <returns></returns>
        public bool RollBack(WfActivity act)
        {
            if (act == null) return false;

            var obj = new[]
                {
                    new OracleParameter("var_actid", OracleDbType.Int32) {Value = act.ID}, //0
                    new OracleParameter("var_ownerid", OracleDbType.Int32) {Value = act.LockOwner}, //1
                    new OracleParameter("isok", OracleDbType.Int32, ParameterDirection.Output), //2
                    new OracleParameter("forzenacts", OracleDbType.NVarchar2, 500), //3
                    new OracleParameter("rollbackacts", OracleDbType.NVarchar2, 500) //4
                };
            obj[3].Direction = ParameterDirection.Output;
            obj[4].Direction = ParameterDirection.Output;

            //---------------执行存储过程------------------
            DB.ExecuteProc("actrollback", obj);
            if (int.Parse(obj[2].Value.ToString()) > -1)
            {
                //---冻结状态活动
                string strs = obj[3].Value.ToString();
                if (!string.IsNullOrEmpty(strs) && strs.IndexOf(';') > -1)
                {
                    string[] list = strs.Split(';');
                    int count = list.Length - 1;
                    //移除内存中状态为数据库状态已经被更新为frozen的活动
                    try
                    {
                        for (int i = 0; i < count; i++)
                        {
                            _newActs.Remove(GetCollectionAct(_newActs, int.Parse(list[i])));
                            _acts.Remove(GetCollectionAct(_acts, int.Parse(list[i])));
                        }
                    }
                    catch
                    {
                        return false;
                    }
                }
                //---------------回滚状态活动---------------
                strs = obj[4].Value.ToString();
                if (!string.IsNullOrEmpty(strs) && strs.IndexOf(';') > -1)
                {
                    string[] list = strs.Split(';');
                    int count = list.Length - 1;
                    //移除内存中状态为数据库状态已经被更新为frozen的活动
                    try
                    {
                        for (int i = 0; i < count; i++)
                        {
                            GetActivity(int.Parse(list[i]), WfFieldCode.DbNone);
                        }
                    }
                    catch
                    {
                        return false;
                    }
                }
            }
            else
            {
                return false;
            }
            return true;
        }

        #endregion 中国特有模式 回退
    }
}